package rules;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import components.Component;

import managers.ComponentManager;
import managers.SemanticsManager;

import org.jdom2.Element;

public class Rule {
	
	private String name;
	private String group;
	private ArrayList<Component> matchingCriteria;
	private ArrayList<Action> outputActions;
	
	
	public String getName(){
		return name;
	}
	
	public void setName(String name){
		this.name = name;
	}
	
	public String getGroupName(){
		return group;
	}
	
	public void setGroupName(String group){
		this.group = group;
	}
	
	public ArrayList<Component> getMatchingCriteria(){
		return matchingCriteria;
	}
	
	public Component getMatchingCriterion(int index){
		return matchingCriteria.get(index);
	}
	
	
	public void addCriterion(Component input){
		if(matchingCriteria == null)
			matchingCriteria = new ArrayList<Component>();
		
		matchingCriteria.add(input);
	}
	
	public ArrayList<Action> getOutputActions(){
		return outputActions;
	}
	
	public Action getOutputAction(int index){
		return outputActions.get(index);
	}
	
	public void addAction(Action input){
		if(outputActions == null)
			outputActions = new ArrayList<Action>();
		
		outputActions.add(input);
	}
	
	public Element generateXMLElement(){
		Element rule = new Element("rule");
	
		rule.setAttribute("name",name);
		rule.setAttribute("group",group);
		Element input = new Element("matching-criteria");
		if(matchingCriteria != null && matchingCriteria.size() != 0)
			for(Component component : matchingCriteria)
				if(ComponentManager.getInstance().isLeaf(component.getName()))
					input.addContent(((RuleInputLeaf)component).generateXMLElement());
				else
					input.addContent(((RuleInputPhrase)component).generateXMLElement());
		rule.addContent(input);
		
		Element output = new Element("output-actions");
		if(outputActions != null && outputActions.size() != 0)
			for(Action action : outputActions)
				output.addContent(action.getXMLElement());
		rule.addContent(output);
		
		return rule;
	}
	
	public Component createCriteria(Element e) {
		String componentName = e.getAttributeValue("name");

		int tag;
		if(e.getAttributeValue("tag") == null)
			tag = -1;
		else
			tag = Integer.parseInt(e.getAttributeValue("tag"));
		
		boolean isOptional = Boolean.parseBoolean(e.getAttributeValue("isOptional"));
		
		if(ComponentManager.getInstance().isLeaf(componentName)){
			RuleInputLeaf leaf = new RuleInputLeaf(e);
			
			leaf.setOptional(isOptional);
			leaf.setTag(tag);
			
			return leaf;
		}
		else{
			List<Element> childrenElements = (List<Element>)e.getChildren(SemanticsManager.COMPONENT);
			if(childrenElements == null)
				childrenElements = new ArrayList<Element>();

			RuleInputPhrase phrase = new RuleInputPhrase(e);
			
			phrase.setOptional(isOptional);
			phrase.setTag(tag);
			
			for(Element child: childrenElements)
				phrase.addChild(createCriteria(child));
			
			return phrase;
		}
	}
	
	public boolean checkAndApply(Component input){
		HashMap<Integer, Component> tagMap = null;
		
		for(Component pattern : this.matchingCriteria){
			tagMap = RuleMatcher.checkAndUnify(pattern, input);
			if(tagMap != null)
				break;
		}

		if(tagMap != null){
			for(Action action: this.outputActions)
				action.applyAction(tagMap);
				
			return true;
		}
		else
			return false;
	}
}
